Chrome 擴充功能:eyeo'測試服務工作人員停權作業的流程

Aga Czyżewska
Aga Czyżewska
Rowan Deysel
Rowan Deysel

聯絡的目的

從 Manifest V2 轉換至 Manifest V3 的過程有基本的改變。在 Manifest V2 中,擴充功能位於背景頁面。背景頁面管理擴充功能和網頁之間的通訊。Manifest V3 改為使用 Service Worker。

我們將在這篇文章中探討測試擴充功能服務 Worker 的問題。具體來說,我們會探討如何確保產品可在服務工作人員遭到停權時正常運作。

我們是誰?

eyeo 公司致力於為使用者、瀏覽器、廣告客戶和發布商提供平衡且永續的線上價值交換服務。目前已有超過 3 億名使用者允許顯示 Acceptable Ads,這項獨立延伸廣告標準以判定廣告是否可接受及避免干擾。

我們的 Extension Engine 團隊提供廣告篩選技術,可支援市面上一些最熱門的廣告封鎖瀏覽器擴充功能,例如 AdBlock 和 Adblock Plus,為全球有超過 1 億名使用者。此外,我們也以開放原始碼程式庫提供這項技術,以便用於其他廣告篩選瀏覽器擴充功能。

什麼是 Service Worker?

擴充功能服務工作站是瀏覽器擴充功能的中央事件處理常式。並在背景中獨立執行。大致上沒有問題。我們可以在新服務工作人員的背景網頁上執行大部分所需的作業。但與背景頁面相比,則有以下幾項變更:

  • Service Worker 會在不使用時終止。因此,我們必須保留應用程式狀態,而非依賴全域變數。這意味著我們系統的任何進入點都必須準備好在系統初始化之前呼叫。
  • 必須先附加事件監聽器,再等待任何非同步回呼。遭到停權的服務工作人員仍可接收已訂閱的事件。如果事件的接聽程式沒有在第一次轉輪事件迴圈中註冊,如果事件喚醒 Service Worker,就不會收到該事件。
  • 閒置終止功能可能會中斷計時器,以免計時器倒數完畢。

Service Worker 何時會遭到停權?

針對 Chrome 119 版,我們曾遇到以下情形,導致 Service Worker 遭到停權:

  • 30 秒未收到事件或呼叫擴充功能 API 後
  • 如果開發人員工具已開啟,或者您使用的是 Chrome Driver 測試程式庫,請勿這麼做 (查看功能要求)。
  • 只要在 chrome://serviceworker-internals 中按一下「Stop」即可。

如需最新資訊,請參閱服務工作站生命週期

為什麼會測試這個問題?

建議您提供正式指引,瞭解如何「以有效率的方式測試服務員工」,或是提供可執行的測試範例,相信會很有幫助。在測試服務工作人員的過程中,我們遇到了以下幾項挑戰:

  • 測試擴充功能中有狀態服務工作處理程序停止時,我們會遺失其狀態及其已註冊的事件。我們要如何在測試流程中保存資料?
  • 如果服務工作處理程序隨時可能暫停,我們必須測試中斷的所有功能,確認能否正常運作。
  • 即使我們在測試中引入會隨機暫停服務 Worker 的機制,瀏覽器卻沒有可輕鬆暫停服務工作站的 API。我們已要求 W3C 團隊新增這項功能,但這是正在進行的對話。

測試 Service Worker 停權

我們嘗試了多種在測試期間觸發服務工作處理程序停權的方法:

做法 方法相關問題
任意等待時間 (例如 30 秒) 導致測試速度緩慢且不可靠,尤其是執行多項測試時。由於 WebDriver 使用 Chrome 的 DevTools API,而且開啟 DevTools 時,這個服務工作處理程序並未暫停,因此 WebDriver 的運作不正常。即使我們可以略過這個步驟,我們還是必須檢查 Service Worker 是否遭到停權,而我們沒有辦法這麼做。
在 Service Worker 中執行無限迴圈 根據規格,這可能會導致瀏覽器終止,實際情況取決於瀏覽器的實作這項功能的方式。在這種情況下,Chrome 不會終止 Service Worker,因此無法測試服務工作處理程序暫停時的情況。
讓 Service Worker 顯示訊息,以檢查停權狀態 傳送訊息會喚醒 Service Worker。這項功能可以用來檢查 Service Worker 是否處於休眠狀態,但會在暫停 Service Worker 後立即完成檢查,因此會導致測試結果中斷。
使用 chrome.processes.terminate() 終止 Service Worker 程序 擴充功能的服務工作處理程序會與擴充功能的其他部分共用程序,因此使用 chrome.process.terminate() 或 Chrome 的處理程序管理員 GUI 終止這項程序,不僅會終止服務工作處理程序,也會終止任何擴充功能頁面。

我們最終會執行一項測試,用 Selenium WebDriver 開啟 chrome://serviceworker-internals/,按一下 Service Worker 的「停止」按鈕,檢查程式碼會如何回應遭到停權的服務工作處理程序。

這是目前為止的最佳做法,但並非理想的情況,因為我們的 Mocha 測試 (在擴充功能頁面執行) 無法自行完成,因此需要傳回指向 WebDriver 節點程式。也就是說,這些測試無法只透過擴充功能執行,必須使用 Selenium WebDriver 來觸發。

以下圖表展示我們如何透過不同流程與瀏覽器 API 通訊,以及新增「暫停服務工作站」機制對瀏覽器 API 的影響。

顯示測試流程的圖表
在 Service Worker 暫停的情況下測試流程。

我們在暫停服務工作處理程序 (藍色) 的新流程中,新增了 Selenium WebDriver,可於使用者介面執行「點選」操作,觸發在瀏覽器 API 中的操作。

值得注意的是,Chrome 錯誤是使用 Selenium WebDriver 進行這項操作,導致服務工作人員無法重新啟動。這項功能已在 Chrome 116 中修正,但現在也有解決方法:將 Chrome 在每個分頁中自動開啟開發人員工具,即可讓 Service Worker 正確啟動。

由於點選按鈕並非穩定 API,且開啟開發人員工具 (適用於舊版瀏覽器) 似乎會導致效能降低,因此,雖然測試不夠理想,我們仍然會使用這個方法。

我們要如何涵蓋完整功能?模糊測試

訂立測試停權機制後,我們必須決定如何插入自動化測試套件。我們的標準測試是在每次與背景網頁互動之前,WebDriver 會在 chrome://serviceworker-internals/ 網頁上的「停止」上按一下「停止」,就是在一個環境中執行標準測試,

模糊測試執行範例
圖片:顯示目前測試設定。

由於停權機制不穩定,有時會導致不穩定的測試,所以大部分測試都會執行,而非所有測試。此外,以模糊模式執行所有測試套件需要很長的時間。因此,我們選擇了在模糊模式中測試最重要的路徑,而非涵蓋所有「類似」情況。值得一提的是,在「模糊模式」中執行功能測試代表我們必須增加測試逾時,因為暫停或重新啟動服務 Worker 需要更多時間。

這些測試可以做為概略的第一項傳遞,其中突顯了程式碼失敗的許多地方,但不一定能找到服務工作處理程序暫停造成作業中斷的所有細微方法。

在內部,我們將這類測試稱為「模糊測試」。傳統上,模糊測試是指在程式中擲回無效的輸入,確保其回應合理,或至少不會當機。就本例而言,「輸入無效」是指 Service Worker 隨時遭到停權的指令,而我們預期「合理行為」是指廣告篩選功能必須如往常一樣運作。這並不是無效的輸入內容,因為這是 Manifest V3 中的預期行為,但在 Manifest V2 中卻無效,因此這是合理的術語。

摘要

在 Manifest V3 (宣告式 NetRequest 規則除外) 中,服務工作處理程序是最大的變化之一。遷移至 Manifest V3 可能需要對瀏覽器擴充功能和新測試方式進行多項程式碼變更。此外,具備永久狀態的擴充功能開發人員也必須備妥擴充功能,以優雅的方式處理非預期服務工作中斷的情況。

很遺憾,沒有任何 API 可以針對用途輕鬆處理停權事宜。我們想要在早期階段測試擴充功能程式碼集的可靠性,並防範停權機制,因此必須設法解決。其他遇到類似挑戰的擴充功能開發人員可以使用這個解決方法。雖然在開發與維護階段都相當耗時,因此我們可以確保擴充功能可以在服務工作人員定期暫停的環境中順利執行。

雖然已有對測試服務工作工作站停權的基本支援,但我們希望未來能夠透過擴充功能測試服務工作人員的平台支援,因為這麼做可大幅縮短測試執行時間和維護工作。